/**
 * Redis缓存中间件
 * 用于缓存API响应，减轻数据库压力
 */
const redis = require('../db/redis');
const crypto = require('crypto');

/**
 * 默认配置
 */
const defaultOptions = {
  expire: 60,              // 缓存过期时间（秒）
  prefix: 'api:cache:',    // 缓存键前缀
  debug: true,            // 调试模式，默认开启
  dependencies: []        // 缓存依赖关系
};

/**
 * 生成缓存键
 * @param {Object} ctx - Koa上下文
 * @param {Object} options - 缓存选项
 * @returns {String} 缓存键
 */
function generateCacheKey(ctx, options) {
  const method = ctx.method;
  const path = ctx.path;
  
  // 创建查询参数对象的副本并排序
  const query = { ...ctx.query };
  const queryString = Object.keys(query)
    .sort()
    .map(key => `${key}=${query[key]}`)
    .join('&');
  
  // 生成缓存键
  let cacheKey = `${options.prefix}${method}:${path}`;
  
  // 添加查询参数到缓存键
  if (queryString) {
    // 对长查询字符串进行哈希处理
    const hash = crypto
      .createHash('md5')
      .update(queryString)
      .digest('hex');
    
    cacheKey += `:${hash}`;
  }
  
  return cacheKey;
}

/**
 * 使相关缓存失效
 * @param {String} pattern - 缓存键模式
 */
async function invalidateCache(pattern) {
  try {
    const keys = await redis.client.keys(pattern);
    if (keys.length > 0) {
      await redis.client.del(keys);
      console.log(`🔄 已清除缓存: ${keys.length} 个键`);
    }
  } catch (err) {
    console.error('清除缓存失败:', err);
  }
}

/**
 * 创建缓存中间件
 * @param {Object} userOptions - 用户自定义选项
 */
function cacheMiddleware(userOptions = {}) {
  // 合并默认选项和用户选项
  const options = { ...defaultOptions, ...userOptions };
  
  return async (ctx, next) => {
    // 仅缓存GET请求
    if (ctx.method !== 'GET') {
      return await next();
    }
    
    // 生成缓存键
    const cacheKey = generateCacheKey(ctx, options);
    
    // 尝试从缓存获取数据
    const cachedData = await redis.get(cacheKey, true);
    
    if (options.debug) {
      if (cachedData) {
        console.log(`🔵 [Cache HIT] ${ctx.path}${ctx.search || ''}`);
      } else {
        console.log(`🔴 [Cache MISS] ${ctx.path}${ctx.search || ''}`);
      }
    }
    
    if (cachedData) {
      // 缓存命中，直接返回缓存的数据
      ctx.body = cachedData;
      return;
    }
    
    // 记录请求开始时间
    const startTime = Date.now();
    
    // 缓存未命中，继续处理请求
    await next();
    
    // 计算请求处理时间
    const responseTime = Date.now() - startTime;
    
    // 如果响应成功且有数据，则缓存结果
    if (ctx.status === 200 && ctx.body) {
      // 仅缓存返回了code: 200/0的成功响应
      const responseCode = ctx.body.code;
      if (responseCode === 200 || responseCode === 0) {
        await redis.set(cacheKey, ctx.body, options.expire);
        
        if (options.debug) {
          console.log(`🟢 [Cache STORED] ${ctx.path}${ctx.search || ''} (${options.expire}s) - 响应时间: ${responseTime}ms`);
        }
      }
    }
  };
}

// 导出缓存中间件和工具函数
module.exports = Object.assign(cacheMiddleware, {
  invalidateCache,
  generateCacheKey
}); 